

#ifndef Vector4_h
#define Vector4_h


#include <Defines.h>
#include <CSharpPropertyMethods.h>

#include <System/Collections/Generic/IEquatable.h>
#include <System/Array.h>
#include <System/String.h>
#include <System/Math.h>

#include "RMathHelper.h"
#include "Vector2.h"
#include "Vector3.h"
#include "RQuaternion.h"

// TODO: Declerate fixa includes.

namespace Riccsson
{
	namespace Xna
	{
		namespace Framework
		{
            // Forward declerations.
            struct Matrix;

            struct Vector4
				: public Riccsson::System::Collections::Generic::IEquatable<Vector4>
            {
                #pragma region private: Fields

                private: static const Vector4& zeroVector;
                private: static const Vector4& unitVector;
                private: static const Vector4& unitXVector;
                private: static const Vector4& unitYVector;
                private: static const Vector4& unitZVector;
                private: static const Vector4& unitWVector;

                #pragma endregion private: Fields


                #pragma region public: Fields

                public: float X;
                public: float Y;
                public: float Z;
                public: float W;

                #pragma endregion public: Fields


                #pragma region Properties

                //public: static Vector4 Zero
                //{
                //    get { return zeroVector; }
                //}
                //
                //public: static Vector4 One
                //{
                //    get { return unitVector; }
                //}
                //
                //public: static Vector4 UnitX
                //{
                //    get { return unitXVector; }
                //}
                //
                //public: static Vector4 UnitY
                //{
                //    get { return unitYVector; }
                //}
                //
                //public: static Vector4 UnitZ
                //{
                //    get { return unitZVector; }
                //}
                //
                //public: static Vector4 UnitW
                //{
                //    get { return unitWVector; }
                //}

                #pragma endregion Properties


                #pragma region Constructors
                
			    public: Vector4();
                public: Vector4(float x, float y, float z, float w);
                public: Vector4(Vector2 value, float z, float w);
                public: Vector4(Vector3 value, float w);
                public: Vector4(float value);

                #pragma endregion


                #pragma region public: Methods

                public: static Vector4 Add(Vector4 value1, Vector4 value2);
                public: static void Add(Vector4 ref value1, Vector4 ref value2, Vector4 out result);
                public: static Vector4 Barycentric(Vector4 value1, Vector4 value2, Vector4 value3, float amount1, float amount2);
                public: static void Barycentric(Vector4 ref value1, Vector4 ref value2, Vector4 ref value3, float amount1, float amount2, Vector4 out result);
                public: static Vector4 CatmullRom(Vector4 value1, Vector4 value2, Vector4 value3, Vector4 value4, float amount);
                public: static void CatmullRom(Vector4 ref value1, Vector4 ref value2, Vector4 ref value3, Vector4 ref value4, float amount, Vector4 out result);
                public: static Vector4 Clamp(Vector4 value1, Vector4 min, Vector4 max);
                public: static void Clamp(Vector4 ref value1, Vector4 ref min, Vector4 ref max, Vector4 out result);
                public: static float Distance(Vector4 value1, Vector4 value2);
                public: static void Distance(Vector4 ref value1, Vector4 ref value2, float out result);
                public: static float DistanceSquared(Vector4 value1, Vector4 value2);
                public: static void DistanceSquared(Vector4 ref value1, Vector4 ref value2, float out result);
                public: static Vector4 Divide(Vector4 value1, Vector4 value2);
                public: static Vector4 Divide(Vector4 value1, float divider);
                public: static void Divide(Vector4 ref value1, float divider, Vector4 out result);
                public: static void Divide(Vector4 ref value1, Vector4 ref value2, Vector4 out result);
                public: static float Dot(Vector4 vector1, Vector4 vector2);
                public: static void Dot(Vector4 ref vector1, Vector4 ref vector2, float out result);
                public: override bool Equals(const Riccsson::System::object* obj) const;
                public: bool Equals(const Vector4* other) const;
                public: override int GetHashCode();
                public: static Vector4 Hermite(Vector4 value1, Vector4 tangent1, Vector4 value2, Vector4 tangent2, float amount);
                public: static void Hermite(Vector4 ref value1, Vector4 ref tangent1, Vector4 ref value2, Vector4 ref tangent2, float amount, Vector4 out result);
                public: float Length();
                public: float LengthSquared();
                public: static Vector4 Lerp(Vector4 value1, Vector4 value2, float amount);
                public: static void Lerp(Vector4 ref value1, Vector4 ref value2, float amount, Vector4 out result);
                public: static Vector4 Max(Vector4 value1, Vector4 value2);
                public: static void Max(Vector4 ref value1, Vector4 ref value2, Vector4 out result);
                public: static Vector4 Min(Vector4 value1, Vector4 value2);
                public: static void Min(Vector4 ref value1, Vector4 ref value2, Vector4 out result);
                public: static Vector4 Multiply(Vector4 value1, Vector4 value2);
                public: static Vector4 Multiply(Vector4 value1, float scaleFactor);
                public: static void Multiply(Vector4 ref value1, float scaleFactor, Vector4 out result);
                public: static void Multiply(Vector4 ref value1, Vector4 ref value2, Vector4 out result);
                public: static Vector4 Negate(Vector4 value);
                public: static void Negate(Vector4 ref value, Vector4 out result);
                public: static Vector4 Normalize(Vector4 vector);
                public: static void Normalize(Vector4 ref vector, Vector4 out result);
                public: void Normalize();
                public: static Vector4 SmoothStep(Vector4 value1, Vector4 value2, float amount);
                public: static void SmoothStep(Vector4 ref value1, Vector4 ref value2, float amount, Vector4 out result);
                public: static Vector4 Subtract(Vector4 value1, Vector4 value2);
                public: static void Subtract(Vector4 ref value1, Vector4 ref value2, Vector4 out result);
                public: static Vector4 Transform(Vector2 position, Matrix& matrix);
                public: static Vector4 Transform(Vector3 position, Matrix& matrix);
                public: static Vector4 Transform(Vector4 vector, Matrix& matrix);
                public: static void Transform(Vector2 ref position, Matrix ref matrix, Vector4 out result);
                public: static void Transform(Vector3 ref position, Matrix ref matrix, Vector4 out result);
                public: static void Transform(Vector4 ref vector, Matrix ref matrix, Vector4 out result);
                public: override GC_PTR<Riccsson::System::string> ToString() const;

                #pragma endregion public: Methods


                
            };

            #pragma region Operators

            //Vector4 operator -(Vector4 value);
            //bool operator ==(const Vector4& value1,const Vector4& value2);
            //bool operator !=(Vector4 value1, Vector4 value2);
            //Vector4 operator +(Vector4 value1, Vector4 value2);
            //Vector4 operator -(Vector4 value1, Vector4 value2);
            //Vector4 operator *(Vector4 value1, Vector4 value2);
            //Vector4 operator *(Vector4 value1, float scaleFactor);
            //Vector4 operator *(float scaleFactor, Vector4 value1);
            //Vector4 operator /(Vector4 value1, Vector4 value2);
            //Vector4 operator /(Vector4 value1, float divider);
			inline Vector4 operator -(Vector4 value)
			{
				return Vector4(-value.X, -value.Y, -value.Z, -value.W);
			}

			inline bool operator ==(const Vector4& value1,const Vector4& value2)
			{
				return value1.W == value2.W
					&& value1.X == value2.X
					&& value1.Y == value2.Y
					&& value1.Z == value2.Z;
			}

			inline bool operator !=(Vector4 value1, Vector4 value2)
			{
				return !(value1.W == value2.W
					&& value1.X == value2.X
					&& value1.Y == value2.Y
					&& value1.Z == value2.Z);
			}

			inline Vector4 operator +(Vector4 value1, Vector4 value2)
			{
				value1.W += value2.W;
				value1.X += value2.X;
				value1.Y += value2.Y;
				value1.Z += value2.Z;
				return value1;
			}

			inline Vector4 operator -(Vector4 value1, Vector4 value2)
			{
				value1.W -= value2.W;
				value1.X -= value2.X;
				value1.Y -= value2.Y;
				value1.Z -= value2.Z;
				return value1;
			}

			inline Vector4 operator *(Vector4 value1, Vector4 value2)
			{
				value1.W *= value2.W;
				value1.X *= value2.X;
				value1.Y *= value2.Y;
				value1.Z *= value2.Z;
				return value1;
			}

			inline Vector4 operator *(Vector4 value1, float scaleFactor)
			{
				value1.W *= scaleFactor;
				value1.X *= scaleFactor;
				value1.Y *= scaleFactor;
				value1.Z *= scaleFactor;
				return value1;
			}

			inline Vector4 operator *(float scaleFactor, Vector4 value1)
			{
				value1.W *= scaleFactor;
				value1.X *= scaleFactor;
				value1.Y *= scaleFactor;
				value1.Z *= scaleFactor;
				return value1;
			}

			inline Vector4 operator /(Vector4 value1, Vector4 value2)
			{
				value1.W /= value2.W;
				value1.X /= value2.X;
				value1.Y /= value2.Y;
				value1.Z /= value2.Z;
				return value1;
			}

			inline Vector4 operator /(Vector4 value1, float divider)
			{
				float factor = 1.0f / divider;
				value1.W *= factor;
				value1.X *= factor;
				value1.Y *= factor;
				value1.Z *= factor;
				return value1;
			}

            #pragma endregion Operators
        }
    }
}

#endif